local skynet = require "skynet"
local filename = "slotmgr.lua"
local filelog = require "filelog"
local queue = require "skynet.queue"
local base = require "base"
local redisdao = require "redisdao"
local tabletool = require "tabletool"
local json = require "cjson"
json.encode_sparse_array(true,1,1)

local SlotTool = require "slottool"
require "lhdaenum"

------------
--枚举类

--扑克牌组数
local CardPairNum = 1           --1副牌，每副52张，共计52张

--扑克牌定义
--百位表示花色：1方块 2梅花 3红桃 4黑桃;末2位表示牌值1-A 11-J 12-Q 13—K 3~10-3~10
local CardData = {
    101,102,103,104,105,106,107,108,109,110,111,112,113,
    201,202,203,204,205,206,207,208,209,210,211,212,213,
    301,302,303,304,305,306,307,308,309,310,311,312,313,
    401,402,403,404,405,406,407,408,409,410,411,412,413,
}

--系统输钱上限基值,默认10万
local SystemLoseLimit_Base = 1000000

--系统输钱上限控制系数
local SystemLoseLimit_Factor = 0.08

--开奖类型
local LotteryType = {
    LOTTERY_TYPE_BEST = 1,      --最优开奖
    LOTTERY_TYPE_BAD = 2,       --较差开奖
    LOTTERY_TYPE_NORMAL = 3,    --正常开奖
}

--图标类型
local Picture_type = {
    PICTURE_TYPE_NORMAL = 1,    --普通图标
}

--图标subid（不计类型）
local Picture_subid = {
    101,    --庄
    102,    --闲
    103,    --平
    104,    --六
}

--图标id
local Picture_id = {
    1101,    --庄
    1102,    --闲
    1103,    --平
    1104,    --六
}

--特殊奖励定义
local SpecialPrize = {

}

--额外奖励类型列表（所有奖励）
--lhdenum.lua中有对应定义
local Extra_prize_type = {
    SPECIAL_PRIZE_LIU = 1104,
}

----------------------
--数据表，可以改变

--倍率列表
--key为：图标id = 图标类型 + 图标subid
--[1101] = 0 表示：庄的赔率为2倍
--
local Odds_list = {
    [1101] = 2,     --庄
    [1102] = 2,     --闲
    [1103] = 9,     --平
    [1104] = 7,     --六
}

--图标权重列表
local Weight_list = {
    [1101] = 90,  --庄4500
    [1102] = 90,  --闲4500
    [1103] = 10,  --平500
}

--系统库存概率表
--S = 库存值
local S_list = {
    [1] = { -- S < -500万
        nohit = 1.00,   --必不中概率
        normal = 0.00,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [2] = { -- -500万<=S<-100万
        nohit = 0.80,   --必不中概率
        normal = 0.20,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [3] = { -- -100万<=S<-20万
        nohit = 0.60,   --必不中概率
        normal = 0.40,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [4] = { -- -20万<=S<-10万
        nohit = 0.30,   --必不中概率
        normal = 0.70,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [5] = { -- -10万<=S<200万
        nohit = 0.00,   --必不中概率
        normal = 1.00,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [6] = { -- 200万<=S<1000万
        nohit = 0.00,   --必不中概率
        normal = 0.80,  --正常开奖概率
        hit = 0.20,     --必中概率
    },
    [7] = { -- 1000万<=S<5000万
        nohit = 0.00,   --必不中概率
        normal = 0.60,  --正常开奖概率
        hit = 0.40,     --必中概率
    },
    [8] = { -- 5000万<=S<1亿
        nohit = 0.00,   --必不中概率
        normal = 0.50,  --正常开奖概率
        hit = 0.50,     --必中概率
    },
    [9] = { -- S>=1亿
        nohit = 0.00,   --必不中概率
        normal = 0.40,  --正常开奖概率
        hit = 0.60,     --必中概率
    },
}

--特殊奖励权值表
local SPrize_weight_list = {
    
}

--开奖权值表
local Jackpot_weight_list = {
    [0] = {
        [1] = 100,  --中奖励1的权重
        [2] = 0,    --中奖励2的权重
        [3] = 0,    --中奖励3的权重
        [4] = 0,    --中奖励4的权重
        [5] = 0,    --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [1] = {
        [1] = 80,   --中奖励1的权重
        [2] = 20,   --中奖励2的权重
        [3] = 0,    --中奖励3的权重
        [4] = 0,    --中奖励4的权重
        [5] = 0,    --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [2] = {
        [1] = 60,   --中奖励1的权重
        [2] = 30,   --中奖励2的权重
        [3] = 10,   --中奖励3的权重
        [4] = 0,    --中奖励4的权重
        [5] = 0,    --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [3] = {
        [1] = 50,   --中奖励1的权重
        [2] = 30,   --中奖励2的权重
        [3] = 10,   --中奖励3的权重
        [4] = 10,   --中奖励4的权重
        [5] = 0,    --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [4] = {
        [1] = 40,   --中奖励1的权重
        [2] = 30,   --中奖励2的权重
        [3] = 20,   --中奖励3的权重
        [4] = 10,   --中奖励4的权重
        [5] = 0,    --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [5] = {
        [1] = 30,   --中奖励1的权重
        [2] = 30,   --中奖励2的权重
        [3] = 20,   --中奖励3的权重
        [4] = 10,   --中奖励4的权重
        [5] = 10,   --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [6] = {
        [1] = 10,   --中奖励1的权重
        [2] = 20,   --中奖励2的权重
        [3] = 20,   --中奖励3的权重
        [4] = 20,   --中奖励4的权重
        [5] = 20,   --中奖励5的权重
        [6] = 10    --中奖励6的权重
    },
}

--奖池奖励列表
local Jackpot_award_list = {
    [1] = 1,    --获取奖池1%
    [2] = 5,    --获取奖池5%
    [3] = 8,    --获取奖池8%
    [4] = 10,   --获取奖池10%
    [5] = 15,   --获取奖池15%
    [6] = 20,   --获取奖池20%
}


--------------------------
--辅助表

--图标概率表，由权重表生成
local Prob_list = nil

--图标总权值,，由权重表生成
local Total_weight = nil

-------------------------------
-------------------------------
---工具类

--更新图标概率表
function SlotTool.update_picture_prob_list()
    local prob_list = {}

    local total_prob = 0
    local total_weight = SlotTool.calculate_total_weight(Weight_list)
    for id,w in pairs(Weight_list) do
        prob_list[id] = w / total_weight
        total_prob = total_prob + prob_list[id]
    end
        
    --总概率应为1
    if math.floor(total_prob * 100) ~= 100 then
        filelog.sys_error("total probability not equal to 1!",total_prob)
    end

    return prob_list,total_weight
end

--
--获取开奖类型
--返回 LotteryType类型
--
function SlotTool.get_lottery_type(gamename)
    --获取库存值
    local inventory = SlotTool.get_static_inventory_from_redis(gamename)

    local item = nil
    local s = inventory
    local a = 10000
    if s < -500 * a then
        item = S_list[1]
    elseif s >= -500 * a and s < -100 * a then
        item = S_list[2]
    elseif s >= -100 * a and s < -20 * a  then
        item = S_list[3]
    elseif s >= -20 * a and s < -10 * a then
        item = S_list[4]
    elseif s >= -10 * a and s < 200 * a then
        item = S_list[5]
    elseif s >= 200 * a and s < 1000 * a then
        item = S_list[6]
    elseif s >= 1000 * a and s < 5000 * a then
        item = S_list[7]
    elseif s >= 5000 * a and s < 10000 * a then
        item = S_list[8]
    elseif s >= 10000 * a then
        item = S_list[9]
    end

     --根据概率获取随机开奖类型
    local r = base.get_random(1, 1000)
    local hit = math.floor(item.hit * 1000)
    local nohit = hit + math.floor(item.nohit * 1000)
    local normal = nohit + math.floor(item.normal * 1000) 
    if r <= hit then
        return LotteryType.LOTTERY_TYPE_BAD
    elseif r <= nohit then
        return LotteryType.LOTTERY_TYPE_BEST
    elseif r <= normal then
        return LotteryType.LOTTERY_TYPE_NORMAL
    end
end

--
--获取系统输赢列表
--
function SlotTool.get_system_win_lose_list(total_bet_list, total_bet, is_robot_banker)
    local sys_win_list = {}
    local sys_lose_list = {}

    if is_robot_banker then
        for id,_ in pairs(Weight_list) do
            local bet_id = id
            local odds = Odds_list[id]
            if odds > 0 and total_bet_list[bet_id] then
                local rtm = odds * total_bet_list[bet_id]   --返钱数
                if bet_id == ELHDBetBtnId.BET_BTN_ID_TIE then
                    local bet_id_banker = ELHDBetBtnId.BET_BTN_ID_BANKER
                    local bet_id_player = ELHDBetBtnId.BET_BTN_ID_PLAYER
                    rtm = rtm + total_bet_list[bet_id_banker] + total_bet_list[bet_id_player]
                end
                if rtm  < total_bet then
                    table.insert(sys_win_list,id)
                elseif rtm > total_bet then
                    table.insert(sys_lose_list,id)
                end
            end
        end
    else
        for id,_ in pairs(Weight_list) do
            local bet_id = id
            local odds = Odds_list[id]
            if odds > 0 and total_bet_list[bet_id] then
                local rtm = odds * total_bet_list[bet_id]   --返钱数
                if bet_id == ELHDBetBtnId.BET_BTN_ID_TIE then
                    local bet_id_banker = ELHDBetBtnId.BET_BTN_ID_BANKER
                    local bet_id_player = ELHDBetBtnId.BET_BTN_ID_PLAYER
                    rtm = rtm + total_bet_list[bet_id_banker] + total_bet_list[bet_id_player]
                end
                if rtm  > total_bet then
                    table.insert(sys_win_list,id)
                elseif rtm < total_bet then
                    table.insert(sys_lose_list,id)
                end
            end
        end
    end
    
    return sys_win_list,sys_lose_list
end

--
--根据开奖结果，获得庄闲手牌
--一共1副牌
--
function SlotTool.get_random_cards_by_result(result_id)
    local player_cards = {}
    local banker_cards = {}
    local player_points = 0
    local banker_points = 0

    if result_id == ELHDBetBtnId.BET_BTN_ID_TIE then    --平局
        local cts = {1,2,3,4}
        local cv = base.get_random(1,13)
        local ct1 = base.get_random(1,4)
        cts[4],cts[ct1] = cts[ct1],cts[4]
        local r = base.get_random(1,3)
        local ct2 = cts[r]
        local card1 = ct1 * 100 + cv
        local card2 = ct2 * 100 + cv
        table.insert(player_cards,card1)
        table.insert(banker_cards,card2)
    else
        local cvs = {1,2,3,4,5,6,7,8,9,10,11,12,13}
        local ct1 = base.get_random(1,4)
        local cv1 = base.get_random(1,13)
        local maxcard = ct1 * 100 + cv1
        cvs[cv1],cvs[13] = cvs[13],cvs[cv1]
        local ct2 = base.get_random(1,4)
        local r = base.get_random(1,12)
        local cv2 = cvs[r]
        local mincard = ct2 * 100 + cv2
        if cv1 < cv2 then
            maxcard,mincard = mincard,maxcard
        end
        if result_id == ELHDBetBtnId.BET_BTN_ID_BANKER then --庄胜
            table.insert(player_cards,mincard)
            table.insert(banker_cards,maxcard)
        elseif result_id == ELHDBetBtnId.BET_BTN_ID_PLAYER then --闲胜
            table.insert(player_cards,maxcard)
            table.insert(banker_cards,mincard)
        end
    end
    banker_points = banker_cards[1] % 100
    player_points = player_cards[1] % 100
    
    --是否为幸运6
    local ext_prize_list = {}
    if banker_points == 6 or player_points == 6 then
        table.insert(ext_prize_list, ELHDBetBtnId.BET_BTN_ID_LIU)
    end

    local result_list = {
        banker_cards = banker_cards,
        player_cards = player_cards,
        banker_points = banker_points,
        player_points = player_points,
        prize_id = result_id,
        ext_prize_list = ext_prize_list,
    }

    return result_list
end

--
--获得系统输钱上限
--
function SlotTool.get_system_lose_limit(gamename)
    local loselimit = 0
    local S = SlotTool.get_static_inventory_from_redis(gamename)
    if S < 0 then
        loselimit = SystemLoseLimit_Base
    else
        loselimit = math.floor(S * SystemLoseLimit_Factor) + SystemLoseLimit_Base
    end

    return loselimit
end

--
--获取系统最优开奖随机结果
--
function SlotTool.get_best_random_result(sys_win_list, total_bet_list, is_robot_banker)
    if sys_win_list and #sys_win_list > 1 then
        local win_w_list = {}
        local total_weight = 0
        for _,id in pairs(sys_win_list) do
            win_w_list[id] = Weight_list[id]
            if id == ELHDBetBtnId.BET_BTN_ID_TIE and win_w_list[id] >= 2 then
                win_w_list[id] = math.floor(win_w_list[id] / 2)
            end
            total_weight = total_weight + win_w_list[id]
        end
        return SlotTool.get_random_result_by_weightlist(win_w_list,total_weight)
    else
        return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
    end
end

--
--获取系统较差开奖随机结果
--去掉系统超上限亏损项和系统最优开奖（返钱数最小）
--
function SlotTool.get_bad_random_result(sys_lose_list, total_bet_list, gamename, total_bet, is_robot_banker)
    local loselimit = SlotTool.get_system_lose_limit(gamename)
    local random_id_list = tabletool.deepcopy(Weight_list)
    local best_id = SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)

    --去除超上限亏损
    local max_id = 0
    if sys_lose_list and #sys_lose_list > 0 then
        local max_ksz = 0
        for _,id in pairs(sys_lose_list) do
            local bet_id = id
            local rtm = Odds_list[id] * total_bet_list[bet_id]
            if bet_id == ELHDBetBtnId.BET_BTN_ID_TIE then
                rtm = rtm + total_bet - total_bet_list[bet_id]
            end
            local ksz =  total_bet - rtm
            if is_robot_banker and ksz < -loselimit then
                random_id_list[id] = nil
            elseif not is_robot_banker and ksz > loselimit then
                random_id_list[id] = nil
            end
            if max_ksz < math.abs(ksz) then
                max_ksz = math.abs(ksz)
                max_id = id
            end
        end
    end
    random_id_list[best_id] = nil

    --开奖列表为空，返回系统亏损第二大的
    if next(random_id_list) == nil then
        local val = 0
        local ret_id = best_id
        if sys_lose_list and #sys_lose_list > 1 then
            for _,id in pairs(sys_lose_list) do
                if id ~= max_id then
                    local bet_id = id
                    local rtm = Odds_list[id] * total_bet_list[bet_id]
                    if bet_id == ELHDBetBtnId.BET_BTN_ID_TIE then
                        rtm = rtm + total_bet - total_bet_list[bet_id]
                    end
                    local ksz = total_bet - rtm
                    if val < math.abs(ksz) then
                        val = math.abs(ksz)
                        ret_id = id
                    elseif ret_id == ELHDBetBtnId.BET_BTN_ID_TIE 
                    and val == math.abs(ksz) then
                        val = math.abs(ksz)
                        ret_id = id
                    end
                end
            end
        end
        return ret_id
    end

    --只有2个开奖项，减少平概率
    local num = 0
    local tie_id = ELHDBetBtnId.BET_BTN_ID_TIE
    for k,v in pairs(random_id_list) do
        num = num + 1
    end
    if num == 2 and random_id_list[tie_id] then
        random_id_list[tie_id] = math.floor(random_id_list[tie_id] / 5)
    end

    return SlotTool.get_random_result_by_weightlist(random_id_list)
end

--
--获取普通随机结果
--去掉系统超上限亏损项
--
function SlotTool.get_normal_random_result(sys_lose_list, total_bet_list, gamename, total_bet, is_robot_banker)
    local loselimit = SlotTool.get_system_lose_limit(gamename)
    local random_id_list = tabletool.deepcopy(Weight_list)

    --去除超上限亏损
    if sys_lose_list and #sys_lose_list > 0 then
        for _,id in pairs(sys_lose_list) do
            local bet_id = id
            local rtm = Odds_list[id] * total_bet_list[bet_id]
            if bet_id == ELHDBetBtnId.BET_BTN_ID_TIE then
                rtm = rtm + total_bet - total_bet_list[bet_id]
            end
            local ksz =  total_bet - rtm
            if is_robot_banker and ksz < -loselimit then
                random_id_list[id] = nil
            elseif not is_robot_banker and ksz > loselimit then
                random_id_list[id] = nil
            end
        end
    end

    --所有项超上限，则返回最小的
    if next(random_id_list) == nil then
        return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
    end

    --只有2个开奖项，减少平概率
    local num = 0
    local tie_id = ELHDBetBtnId.BET_BTN_ID_TIE
    for k,v in pairs(random_id_list) do
        num = num + 1
    end
    if num == 2 and random_id_list[tie_id] then
        random_id_list[tie_id] = math.floor(random_id_list[tie_id] / 5)
    end

    --产生随机结果
    return SlotTool.get_random_result_by_weightlist(random_id_list)
end

--
--获得纯随机结果
--
function SlotTool.get_real_random_result()
    local banker_cards = {}
    local player_cards = {}
    local card_num = #CardData * CardPairNum
    local indexs = {}
    local banker_points = 0
    local player_points = 0

    --随机获得一张不重复牌
    local function get_random_card_from_cardstack(card_num,indexs)
        indexs = indexs or {}
        local card = nil
        while true do
            local r = base.get_random(1,card_num)
            if not indexs[r] then
                indexs[r] = true
                r = (r - 1) % #CardData + 1
                card = CardData[r]
                break
            end
        end

        return card
    end

    --随机发2张
    for i = 1,2 do
        local card = get_random_card_from_cardstack(card_num,indexs)
        local val = card % 100
        if i % 2 == 0 then  --第2张发给庄家
            table.insert(banker_cards,card)
            banker_points = (banker_points + val) % 100
        else
            table.insert(player_cards,card)
            player_points = (player_points + val) % 100
        end
    end

    --判定开牌结果
    local prize_id = nil
    local ext_prize_list = {}
    if banker_points > player_points then
        prize_id = ELHDBetBtnId.BET_BTN_ID_BANKER
    elseif banker_points < player_points then
        prize_id = ELHDBetBtnId.BET_BTN_ID_PLAYER
    else
        prize_id = ELHDBetBtnId.BET_BTN_ID_TIE
    end
    
    --是否为幸运6
    if banker_points == 6 or player_points == 6 then
        table.insert(ext_prize_list, ELHDBetBtnId.BET_BTN_ID_LIU)
    end
    
    --返回结果
    local result_list = {
        banker_cards = banker_cards,
        player_cards = player_cards,
        banker_points = banker_points,
        player_points = player_points,
        prize_id = prize_id,
        ext_prize_list = ext_prize_list,
    }

    return result_list
end

--
--检测是否超过系统输上限
--
function SlotTool.check_system_loselimit(result_list, total_bet_list, total_bet, gamename, is_robot_banker)
    if result_list.ext_prize_list[1] == nil then
        return result_list
    end
    
    --检测是否超过输上限
    local out_loselimit = false
    local loselimit = SlotTool.get_system_lose_limit(gamename)
    local win_id = result_list.prize_id
    local ext_id = result_list.ext_prize_list[1]
    local rtm = Odds_list[win_id] * total_bet_list[win_id]
    rtm = rtm + Odds_list[ext_id] * total_bet_list[ext_id]
    if win_id == ELHDBetBtnId.BET_BTN_ID_TIE then
        rtm = rtm + total_bet - total_bet_list[win_id]
    end
    local ksz = total_bet - rtm
    if is_robot_banker and ksz < -loselimit then
        out_loselimit = true
    elseif not is_robot_banker and ksz > loselimit then
        out_loselimit = true
    end
    
    --未超过，直接返回
    if not out_loselimit then
        return result_list
    end
    
    --超过输上限，去掉特殊牌,直接牌值都+1
    banker_points = result_list.banker_points
    player_points = result_list.player_points
    if banker_points ~= 5 and banker_points < 13 then
        result_list.banker_points = result_list.banker_points + 1
        result_list.banker_cards[1] = result_list.banker_cards[1] + 1
    end
    if player_points ~= 5 and player_points < 13 then
        result_list.player_points = result_list.player_points + 1
        result_list.player_cards[1] = result_list.player_cards[1] + 1
    end 
    result_list.ext_prize_list = {}
    
    return result_list
end

--
--产生一个随机旋转结果
--
function SlotTool.gen_random_spin_result(gamename, total_bet_list, total_bet, avg_bet, is_robot_banker, is_random)
    local result_id = nil

     --计算系统输赢列表
    local sys_win_list,sys_lose_list = SlotTool.get_system_win_lose_list(total_bet_list,total_bet,is_robot_banker)

    --随机开奖
    if is_random then
        result_id = SlotTool.get_normal_random_result(sys_lose_list,total_bet_list,gamename,total_bet,is_robot_banker)
    else
        --获取开奖类型,分：系统最优开奖，系统较差开奖，随机开奖3种
        local lottery_type = SlotTool.get_lottery_type(gamename)
        if lottery_type == LotteryType.LOTTERY_TYPE_BEST then     --最优开奖
            result_id = SlotTool.get_best_random_result(sys_win_list,total_bet_list,is_robot_banker)
        elseif lottery_type == LotteryType.LOTTERY_TYPE_BAD then  --较差开奖
            result_id = SlotTool.get_bad_random_result(sys_lose_list,total_bet_list,gamename,total_bet,is_robot_banker)
        else    --随机开奖
            result_id = SlotTool.get_normal_random_result(sys_lose_list,total_bet_list,gamename,total_bet,is_robot_banker)
        end
    end

    --根据开牌结果获取随机牌
    local result_list = SlotTool.get_random_cards_by_result(result_id)
    
    --非随机开奖时，检测是否超过输上限
    if not is_random then
        result_list = SlotTool.check_system_loselimit(result_list,total_bet_list,total_bet,gamename,is_robot_banker)
    end

    return result_list
end

--
--获取最小奖励
--
function SlotTool.get_min_spin_result(total_bet_list, is_robot_banker)
    local min_id = 0
    local min_rtm = 100000000000
    if not is_robot_banker then
        min_rtm = 0
    end
    
    --循环每一种情况,求返钱数最小的
    for id,_ in pairs(Weight_list) do
        local bet_id = id
        local odds = Odds_list[id]
        if odds > 0 and total_bet_list[bet_id] then
            local rtm = odds * total_bet_list[bet_id]   --返钱数
            if bet_id == ELHDBetBtnId.BET_BTN_ID_TIE then
                local bet_id_banker = ELHDBetBtnId.BET_BTN_ID_BANKER
                local bet_id_player = ELHDBetBtnId.BET_BTN_ID_PLAYER
                rtm = rtm + total_bet_list[bet_id_banker] + total_bet_list[bet_id_player]
            end
            if is_robot_banker then
                if min_rtm > rtm then
                    min_rtm = rtm
                    min_id = id
                elseif min_rtm == rtm 
                and min_id == ELHDBetBtnId.BET_BTN_ID_TIE then
                    min_rtm = rtm
                    min_id = id
                end
            else
                if min_rtm < rtm then
                    min_rtm = rtm
                    min_id = id
                elseif min_rtm == rtm 
                and min_id == ELHDBetBtnId.BET_BTN_ID_TIE then
                    min_rtm = rtm
                    min_id = id
                end
            end
        end
    end
    
    return min_id
end

--
--获取最大奖励
--
function SlotTool.get_max_spin_result(total_bet_list, is_robot_banker)
    local max_id = 0
    local max_rtm = 0
    if not is_robot_banker then
        max_rtm = 100000000000
    end
    
    --循环每一种情况,求返钱数最大的
    for id,_ in pairs(Weight_list) do
        local bet_id = id
        local odds = Odds_list[id]
        if odds > 0 and total_bet_list[bet_id] then
            local rtm = odds * total_bet_list[bet_id]   --返钱数
            if bet_id == ELHDBetBtnId.BET_BTN_ID_TIE then
                local bet_id_banker = ELHDBetBtnId.BET_BTN_ID_BANKER
                local bet_id_player = ELHDBetBtnId.BET_BTN_ID_PLAYER
                rtm = rtm + total_bet_list[bet_id_banker] + total_bet_list[bet_id_player]
            end
            if is_robot_banker then
                if max_rtm < rtm then
                    max_rtm = rtm
                    max_id = id
                end
            else
                if max_rtm > rtm then
                    max_rtm = rtm
                    max_id = id
                end
            end
        end
    end
    
    return max_id
end


--
--检测随机结果的正确性
--
function SlotTool.check_random_spin_result(spin_result)
    if not spin_result or not spin_result.player_cards 
    or not spin_result.banker_cards then
        return false
    end

    --检测是否有同牌
    if spin_result.player_cards[1] == spin_result.banker_cards[1] then
        filelog.sys_error("-----------have same card------",spin_result)
        return false
    end
    return true
end

--
--处理送灯
--is_seq是否为连续灯
--
function SlotTool.handle_give_lamp(sd_w_list, is_seq)
    local result_list = {}

    --获得送灯数
    local lamp_num = SlotTool.get_random_result_by_weightlist(sd_w_list)
    if not lamp_num then
        return
    end

    --计算总权值
    local total_w = SlotTool.calculate_total_weight(SDFruit_weight_list)

    --随机获取lamp_num盏灯
    if is_seq then  --连续lamp_num盏灯
        local id = SlotTool.get_random_result_by_weightlist(SDFruit_weight_list,total_w)
        table.insert(result_list,id)
        table.insert(result_list,lamp_num)
    else
        for i = 1,lamp_num do
            local id = SlotTool.get_random_result_by_weightlist(SDFruit_weight_list,total_w)
            table.insert(result_list,id)
        end
    end
    
    return result_list
end

--
--处理闪电
--
function SlotTool.handle_lightning(lgtn_w_list)
    local result_list = {}

    --获得翻倍数
    local rate_num = SlotTool.get_random_result_by_weightlist(lgtn_w_list)
    if not rate_num then
        return
    end
    table.insert(result_list,rate_num)

    return result_list
end

--
--根据随机结果获取额外奖励项
--
function SlotTool.get_ext_prize_item(prize_id)
    
end

--
--保存奖励记录
--
function SlotTool.save_prize_records(gamename, opencard_result)
    local records = {}
    local key = (gamename or "") .. "_prize_records"
    local result,data = redisdao.query_data(".gmmqredis", "get", key)
    if result and data then
        records = json.decode(data) or {}
    end
    
    for _,prize_id in pairs(opencard_result) do
        local id = tostring(prize_id)
        records[id] = (tonumber(records[id]) or 0) + 1
    end
    records.total_count = (tonumber(records.total_count) or 0) + 1
    redisdao.query_data(".gmmqredis", "set", key, json.encode(records))

    ---------------------------------

    --辅助函数1
    local function helper_func(val)
        local cnt = 0
        local tmp = val
        while val >= 10 do
            val = math.floor(val / 10)
            cnt = cnt + 1
        end
        if math.floor(10^cnt) == tmp then
            return true
        end
        return false
    end

    --辅助函数2
    local function func(records)
        local porp_list = {}
        local subprop_list = {}
        local cnt = records.total_count or 0
        if cnt == 0 then
            return
        end

        for k,v in pairs(records) do
            if type(v) ~= "table" and k ~= "total_count" then
                v = tonumber(v) or 0
                porp_list[k] = string.format("%g%%",math.floor(v / cnt * 10000) / 100)
            elseif k == "total_count" then
                porp_list[k] = v
            else
                subprop_list[k] = func(v)
            end
        end
        return porp_list,subprop_list
    end

    --开奖次数每增加10倍，统计一次概率
    if helper_func(records.total_count) then
        local porp_list,subprop_list = func(records)
        filelog.sys_obj("prop_list", records.total_count, porp_list, "=================\n", subprop_list)
    end
    ---------------

    return true
end

--
--创建格式化赔率列表
--
function SlotTool.create_format_odds_list()
    local fmt_odds_list = {}

    for id,odds in pairs(Odds_list) do
        local val = tonumber(id) * 10000 + tonumber(odds)
        table.insert(fmt_odds_list,val)
    end
    
    return fmt_odds_list
end

--
--保存赔率列表到文件
--
function SlotTool.save_odds_list_to_file()
    local f = io.open("odds_list.lua","w+")
    if not f then
        filelog.print("open file error!")
        return
    end

    f:write("return { \n")
    for id,odds in pairs(Odds_list) do
        local val = tonumber(id) * 10000 + tonumber(odds)
        f:write(tostring(val) .. ",")
    end
    f:write("}")
    f:close()
end


-------------------------------
----------
--外部接口

local CMD = {}

local cs = queue()

-----------------
----

--
--获取随机旋转结果
--total_bet_list 总下注列表
--total_bet 总下注值
--avg_bet 平均下注值
--is_robot_banker 是否机器人做庄
--is_random 是否随机开奖
--
function CMD.get_random_spin_result(gamename, total_bet_list, total_bet, avg_bet, is_robot_banker, is_random)
    local cnt = 0
    while cnt < 100 do
        local is_ok,spin_result = skynet.pcall(SlotTool.gen_random_spin_result,gamename,total_bet_list,total_bet,avg_bet,is_robot_banker, is_random)
        if is_ok and SlotTool.check_random_spin_result(spin_result) then
            return spin_result
        end
        cnt = cnt + 1
    end

    return false
end

--
--根据随机结果获取额外奖励
--
function CMD.get_ext_prize_result(prize_id)
    local ext_prize_result = {}

    --根据id获取奖励项
    local item = SlotTool.get_ext_prize_item(prize_id)
    if not item then
        return
    end

    --计算总权值
    local total_w = 0
    local w_list = {}
    for key,val in pairs(item) do
        if type(key) == "string" and string.sub(key,-1) == "w" then
            total_w = total_w + val
            w_list[key] = val
        end
    end
    
    --根据权值表，获取随机结果
    local key = SlotTool.get_random_result_by_weightlist(w_list,total_w)
    if not key or key == "failed_w" then
        return
    end

    --获取额外奖励类型
    local len = string.len(key)
    local extprize_name = string.sub(key,1,len - 2)
    local extprize_type = Extra_prize_type[extprize_name]
    if not extprize_type then
        return
    end

    --获取奖励
    local extprize_list = nil
    
    --返回结果
    ext_prize_result.extprize_type = extprize_type
    ext_prize_result.extprize_list = extprize_list

    return ext_prize_result
end

--
--获取开局奖励
--
function CMD.get_start_prize_result(rids)
    local prize_result_list = {}

    if true then
        return {}
    end

    --获取随机结果
    local function get_random_result(prize_list)
        --计算总权值
        local total_w = 0
        local w_list = {}
        for key,val in pairs(prize_list) do
            if type(key) == "string" and string.sub(key,-1) == "w" then
                total_w = total_w + val
                w_list[key] = val
            end
        end
    
        --根据权值表，获取随机结果
        local key = SlotTool.get_random_result_by_weightlist(w_list,total_w)

        return key
    end

    -------------------

     --开火车奖励表
    local drivetrain_list = SPrize_weight_list[SpecialPrize.SPECIAL_PRIZE_KHC]

    --根据权值表，获取随机结果
    local key = get_random_result(drivetrain_list)
    if not key or key == "failed_w" then
        
    else
        local extprize_list = SlotTool.handle_give_lamp(drivetrain_list.sd_w_list,true)
        local item = {
            extprize_type = Extra_prize_type.drivetrain,
            extprize_list = extprize_list,
        }
        table.insert(prize_result_list,item)
    end

    ------------------

    rids = rids or {}
    
    --低于10人不触发
    local player_num = #rids
    if player_num < 10 then
        return prize_result_list
    end

     --判断是否触发鸿运当头
    local goodluck_list = SPrize_weight_list[SpecialPrize.SPECIAL_PRIZE_HYDT]
    local key = get_random_result(goodluck_list)
    if not key or key == "failed_w" then
        return prize_result_list
    end

    --随机选取10%的人中奖
    local prize_coin_list = {}
    local total_w = SlotTool.calculate_total_weight(goodluck_list.coin_w_list)
    local hit_num = math.floor(player_num * 0.1)
    for i = 1,hit_num do
        local k = base.get_random(1,player_num)
        local rid = rids[k]
        local coin_num = SlotTool.get_random_result_by_weightlist(goodluck_list.coin_w_list,total_w)

        prize_coin_list[rid] = coin_num
        rids[k] = rids[player_num]
        table.remove(rids)
        player_num = #rids
    end
    
    if hit_num > 0 then
        local item = {
            extprize_type = Extra_prize_type.goodluck,
            extprize_list = prize_coin_list,
        }
        table.insert(prize_result_list,item)
    end
 
    return prize_result_list
end

--
--处理开奖
--
function CMD.handle_open_jackpot(gamename, jackpot_id, player_list)
    local award_list = {}

    --获取奖池金额
    local jackpot_money = SlotTool.get_jackpot_from_redis(gamename,jackpot_id)

    --随机开奖
    local total_coin = 0
    local max_level = 6
    for _,item in pairs(player_list) do
        local level = math.floor(item.game_num / 5)
        if level > max_level then
            level = max_level
        end
        local w_list = Jackpot_weight_list[level]
        local award_id = SlotTool.get_random_result_by_weightlist(w_list)
        local award_coin = math.floor(Jackpot_award_list[award_id] * jackpot_money * 0.01)
        local award_item = {
            rid = item.rid,
            logo = item.logo,
            rolename = item.rolename,
            award_money_num = award_coin,
        }
        table.insert(award_list, award_item)
        total_coin = total_coin + award_coin
    end
    
    return award_list,total_coin
end

--
--保存奖励记录
--
function CMD.save_prize_records(gamename, opencard_result)
  return cs(SlotTool.save_prize_records,gamename,opencard_result)
end

--
--处理庄家收益
--
function CMD.handle_banker_profit(ganmename, total_bet_num, player_win_num)
    local banker_win = total_bet_num - player_win_num
    return banker_win
end

--
--更新图标权值表
--
function CMD.update_picture_weight_list(new_w_list)
    if type(new_w_list) ~= "table" then
        return false
    end

    for k,v in pairs(new_w_list) do
        if Weight_list[k] and v >= 0 then
            Weight_list[k] = v  
        end
    end
    
    --更新化概率表,总权值
    if next(new_w_list) ~= nil then
        Prob_list,Total_weight_list = SlotTool.update_picture_prob_list()
    end

    return true
end

--
--设置系统输钱上限
--
function CMD.set_system_lose_limit(loselimit_base, loselimit_factor)
    loselimit_base = loselimit_base or 0
    loselimit_factor = loselimit_factor or 0.02
    if loselimit_base < 0 or loselimit_factor < 0 then
        return false
    end
    SystemLoseLimit_Base = loselimit_base
    SystemLoseLimit_Factor = loselimit_factor

    return true
end

--
--处理结算结果
--@total_change 总变化值
--@total_water  总流水值
--@total_bet    玩家总下注
--
function CMD.handle_balance_result(gamename, total_change, total_water, total_bet, comment)
    local tax_rate = SlotTool.get_tax_rate_from_redis(gamename)
    local profit_val = math.floor(total_bet * tax_rate * 100) / 100
    local inventory_val = -total_change

    --更新收益值
    local result1 = SlotTool.update_system_profit(gamename, profit_val, comment)
    if result1 then
        inventory_val = inventory_val - profit_val
    end

    --更新库存值，扣除抽水
    local service_fee_rate = SlotTool.get_service_fee_rate_from_redis(gamename)
    local service_fee_val = math.floor(total_water * service_fee_rate * 100) / 100
    inventory_val = inventory_val - service_fee_val

    return SlotTool.update_system_inventory(gamename, inventory_val, comment)
end

--
--获取抽水率
--
function CMD.get_service_fee_rate(gamename)
    return SlotTool.get_service_fee_rate_from_redis(gamename)
end

-----------
--
--初始化
--
local function init()

    --初始化概率表,总权值
    Prob_list,Total_weight = SlotTool.update_picture_prob_list()

    --保存赔率列表到文件
    SlotTool.save_odds_list_to_file()

    --filelog.print("init slot tool ok!")
end

-------------------
--
skynet.start(function()
    init()
    skynet.dispatch("lua",function(session, source, cmd, ...)
        local f = CMD[cmd]
        if f then
            skynet.retpack(f(...))
        else
            skynet.retpack()
        end
    end)
end)